package com.xiaoyu.lib_av.manager

import `in`.srain.cube.cache.DiskFileUtils
import `in`.srain.cube.concurrent.AppThreads
import `in`.srain.cube.util.CLog
import `in`.srain.cube.util.internal.AppCallback
import android.view.ViewGroup
import com.xiaoyu.base.app.AppContext
import com.xiaoyu.lib_av.datamodel.CallFailType.CallFailTypeDef
import com.xiaoyu.lib_av.datamodel.CallHangUpType.HangUpTypeDef
import com.xiaoyu.lib_av.datamodel.CallMessage
import com.xiaoyu.lib_av.datamodel.CallParams
import com.xiaoyu.lib_av.datamodel.CallResponseType
import com.xiaoyu.lib_av.datamodel.CallResponseType.CallResponseTypeDef
import com.xiaoyu.lib_av.datamodel.CallVendorType.CallVendorTypeDef
import com.xiaoyu.lib_av.listener.IVideoCallLifecycleListener
import com.xiaoyu.lib_av.listener.IVoiceCallLifecycleListener
import com.xiaoyu.lib_av.proxy.AgoraCallProxy
import com.xiaoyu.lib_av.proxy.ICallProxy
import java.io.File

class CallManager private constructor() : IVideoCallLifecycleListener {

    val callRecordCacheDir: DiskFileUtils.CacheDirInfo = DiskFileUtils.getDiskCacheDir(AppContext.getContext(), CALL_CACHE_DIR_NAME, CALL_CACHED_SIZE_IN_KB)

    private lateinit var mProxy: ICallProxy

    private lateinit var singleCallLifecycleListener: IVoiceCallLifecycleListener

    private var mCallLifecycleListener: IVoiceCallLifecycleListener? = null

    @get:CallVendorTypeDef
    val vendorType: String?
        get() = mProxy.vendorType

    val logDir: File?
        get() = mProxy.logDir

    val lastCallRecordFilePath: String?
        get() = mProxy.lastCallRecordFilePath

    var isEnableSpeaker: Boolean?
        get() = mProxy.isEnableSpeaker
        set(enableSpeaker) {
            mProxy.isEnableSpeaker = enableSpeaker == true
        }

    fun init(callLifecycleListener: IVoiceCallLifecycleListener) {
        mProxy = AgoraCallProxy()
        singleCallLifecycleListener = callLifecycleListener
    }

    fun create(lifecycleListener: IVoiceCallLifecycleListener?) {
        mProxy.onCreate()
        mCallLifecycleListener = lifecycleListener
    }

    fun destroy() {
        mProxy.onDestroy()
        mCallLifecycleListener = null
    }

    fun setupLocalVideo(container: ViewGroup) {
        return mProxy.setupLocalVideo(container)
    }

    fun setupRemoteVideo(container: ViewGroup, fuid: String) {
        return mProxy.setupRemoteVideo(container, fuid)
    }

    fun setMute(mute: Boolean) {
        mProxy.setMute(mute)
    }

    fun enableLocalVideo(enable: Boolean) {
        mProxy.enableLocalVideo(enable)
    }

    fun isCalling(fuid: String?): Boolean {
        return mProxy.isCalling(fuid)
    }

    val isCalling: Boolean
        get() = mProxy.isCalling

    val isLocalCalling: Boolean
        get() = mProxy.isLocalCalling

    fun call(params: CallParams, callback: AppCallback<Boolean>?) {
        mProxy.call(params, callback)
    }

    fun response(fuid: String?, @CallResponseTypeDef responseType: String) {
        mProxy.response(fuid, responseType)
    }

    fun hangUp(fuid: String?, @HangUpTypeDef hangupType: String) {
        //TODO:3104 leave it here
        if (!mProxy.isCalling) {
            return
        }
        if (mProxy.isLocalCalling) {
            mProxy.cancelCall(fuid)
        } else {
            mProxy.disconnect(fuid, hangupType)
        }
    }

    override fun onReceiveCall(fromUserId: String, params: CallParams, runnable: Runnable?) {
        if (isCalling) {
            mProxy.response(fromUserId, CallResponseType.BUSY_LINE)
        } else {
            runnable?.run()
            singleCallLifecycleListener.onReceiveCall(fromUserId, params, null)
        }
    }

    fun sendMessage(message: CallMessage) {
        CLog.i(TAG, "sendMessage() message=%s", message)
        mProxy.sendMessage(message)
    }

    override fun onMessageSend(message: CallMessage) {
        CLog.i(TAG, "onMessageSend() message=%s", message)
        AppThreads.runOnMainThread {
            mCallLifecycleListener?.onMessageSend(message)
        }
    }

    override fun onMessageReceive(message: CallMessage) {
        CLog.i(TAG, "onMessageReceive() message=%s", message)
        AppThreads.runOnMainThread {
            mCallLifecycleListener?.onMessageReceive(message)
        }
    }

    override fun onTokenExpired() {
        singleCallLifecycleListener.onTokenExpired()
    }

    override fun onCallFailed(fuid: String, @CallFailTypeDef errorType: String) {
        mCallLifecycleListener?.onCallFailed(fuid, errorType)
    }

    override fun onRespondCall(fuid: String, @CallResponseTypeDef responseType: String) {
        mCallLifecycleListener?.onRespondCall(fuid, responseType)
    }

    override fun onCallResponded(fuid: String, @CallResponseTypeDef responseType: String) {
        mCallLifecycleListener?.onCallResponded(fuid, responseType)
    }

    override fun onCancelCall(fuid: String) {
        mCallLifecycleListener?.onCancelCall(fuid)
    }

    override fun onCallCanceled(callParams: CallParams) {
        singleCallLifecycleListener.onCallCanceled(callParams)
        mCallLifecycleListener?.onCallCanceled(callParams)
    }

    override fun onCallConnecting(fuid: String) {
        mCallLifecycleListener?.onCallConnecting(fuid)
    }

    override fun onCallConnected(fuid: String) {
        mCallLifecycleListener?.onCallConnected(fuid)
    }

    override fun onCallDisconnected(fuid: String, @HangUpTypeDef hangupType: String) {
        CLog.i(TAG, "onCallDisconnected() fuid=%s, hangupType=%s", fuid, hangupType)
        mCallLifecycleListener?.onCallDisconnected(fuid, hangupType)
    }

    override fun onNetStatusReported(good: Boolean, uid: String) {
        mCallLifecycleListener?.onNetStatusReported(good, uid)
    }

    override fun onAudioDeviceChanged(headset: Boolean) {
        mCallLifecycleListener?.onAudioDeviceChanged(headset)
    }

    override fun onStatus(totalDurationInS: Long) {
        mCallLifecycleListener?.onStatus(totalDurationInS)
    }

    override fun onRemoteVideoReceived(fuid: String) {
        (mCallLifecycleListener as? IVideoCallLifecycleListener)?.onRemoteVideoReceived(fuid)
    }

    override fun onLocalAudioMuteStatusChanged(mute: Boolean) {
        mCallLifecycleListener?.onLocalAudioMuteStatusChanged(mute)
    }

    override fun onRemoteAudioMuteStateChanged(fuid: String, mute: Boolean) {
        mCallLifecycleListener?.onRemoteAudioMuteStateChanged(fuid, mute)
    }

    override fun onRemoteVideoDisableStateChanged(fuid: String, disable: Boolean) {
        (mCallLifecycleListener as? IVideoCallLifecycleListener)?.onRemoteVideoDisableStateChanged(fuid, disable)
    }

    override fun onLocateVideoDisableStateChanged(disable: Boolean) {
        (mCallLifecycleListener as? IVideoCallLifecycleListener)?.onLocateVideoDisableStateChanged(disable)
    }

    override fun onLocalVideoFailure() {
        (mCallLifecycleListener as? IVideoCallLifecycleListener)?.onLocalVideoFailure()
    }

    fun stopRecording() {
        mProxy.stopRecording()
    }

    fun switchCamera() {
        mProxy.switchCamera()
    }

    companion object {
        private val TAG = CallManager::class.java.simpleName
        private const val CALL_CACHE_DIR_NAME = "call-cache"
        private const val CALL_CACHED_SIZE_IN_KB = 1024 * 1024.toLong()
        val instance = CallManager()
    }
}